'use strict';

const Parser = require('binary-parser').Parser;
const _ = require('lodash');

class Protocol {
  constructor(buffer) {
    this.buffer = buffer;

    if (!this.verify()) {
      throw new Error('invalid data');
    }

    const parser = new Parser().string('version', {
      length: 3,
      encoding: 'hex',
    }).uint8('mode')
      .uint16('length')
      .uint8('id')
      .uint8('dataType')
      .uint16('dataLength')
      .array('data', {
        type: 'uint8',
        length: 'dataLength',
      })
      .uint8('checksum');
    this.raw = parser.parse(this.buffer);
  }

  static from(buffer) {
    return new Protocol(buffer);
  }

  static fromHex(hex) {
    return new Protocol(new Buffer(hex, 'hex'));
  }

  static fromRaw({ id, mode, dataType, dataHex, data, dataLength }) {
    const length = dataLength + 4;
    let lengthHex = Buffer.from([ length ]).toString('hex');

    if (lengthHex.length < 4) {
      lengthHex = '00' + lengthHex;
    }

    let dataLengthHex = Buffer.from([ dataLength ]).toString('hex');

    if (dataLengthHex.length < 4) {
      dataLengthHex = '00' + dataLengthHex;
    }

    const hex = `55AA00${Buffer.from([ mode ]).toString('hex')}${lengthHex}${Buffer.from([ id ]).toString('hex')}${Buffer.from([ dataType ]).toString('hex')}${dataLengthHex}${dataHex}`;
    console.log(hex);

    const bf = new Buffer(hex, 'hex');
    let sum = 0;
    for (let i = 0; i < bf.length; i++) {
      sum += bf[i];
    }

    const checksum = Buffer.from([ sum % 256 ]).toString('hex');

    console.log(hex + checksum);
    return Protocol.fromHex(hex + checksum);
  }


  toBuffer() {
    return this.buffer;
  }

  toHex() {
    return this.buffer.toString('hex');
  }

  toUtf8String() {
    return this.buffer.toString('utf8');
  }

  verify() {
    const bf = this.buffer;

    let sum = 0;
    for (let i = 0; i < bf.length - 1; i++) {
      sum += bf[i];
    }

    return sum % 256 === bf[bf.length - 1];
  }

  get version() {
    return this.raw.version;
  }

  get mode() {
    return this.raw.mode;
  }

  get length() {
    return this.raw.length;
  }

  get id() {
    return this.raw.id;
  }

  get dataType() {
    return this.raw.dataType;
  }

  get dataLength() {
    return this.raw.dataLength;
  }

  get data() {
    return this.raw.data;
  }

  get checksum() {
    return this.raw.checksum;
  }

  get dataHex() {
    return Buffer.from(this.raw.data).toString('hex');
  }
}

module.exports = Protocol;
